package netClient

import (
	"crypto/tls"
	"errors"
	"fmt"
	"gitee.com/ling-bin/network/netInterface"
	"net"
)

//Client 接口实现，定义一个Server服务类
type Client struct {
	network        string                                                                      //网络类型：tcp  udp
	host           string                                                                      //服务绑定的IP地址和端口
	onConnStart    func(conn netInterface.IConnection)                                         //创建时Hook函数
	onConnStop     func(conn netInterface.IConnection)                                         //连接断开时的Hook函数
	onReceive      func(conn netInterface.IConnection, data []byte)                            //数据上传完成
	onLogHandle    func(level netInterface.ErrLevel, msg string)                               //设置异常处理
	handleStrategy func(conn netInterface.IConnection, data []byte) *netInterface.StrategyData //处理策略,TCP和UDP表现不一样，tcp 只会在连接上第一包数据时调用，udp 会在每一包数上次都调用
	conn           *Connection                                                                 //连接
	config         *Config                                                                     //配置
}

//NewClient 创建一个客户端对象
func NewClient(config *Config) IClient {
	c := &Client{
		network: config.Network,
		host:    config.Host,
		config:  config,
	}
	return c
}

//SetLogHandle 设置日志输出
func (c *Client) SetLogHandle(hookFunc func(level netInterface.ErrLevel, msg string)) {
	c.onLogHandle = hookFunc
}

//SetOnConnStart 设置该client的连接创建时Hook函数
func (c *Client) SetOnConnStart(hookFunc func(netInterface.IConnection)) {
	c.onConnStart = hookFunc
}

//SetOnConnStop 设置该client的连接断开时的Hook函数
func (c *Client) SetOnConnStop(hookFunc func(netInterface.IConnection)) {
	c.onConnStop = hookFunc
}

//SetOnReceive 数据上传完成处理函数[分包后]
func (c *Client) SetOnReceive(hookFunc func(netInterface.IConnection, []byte)) {
	c.onReceive = hookFunc
}

//SetHandleStrategy 设置处理策略
func (c *Client) SetHandleStrategy(hookFunc func(netInterface.IConnection, []byte) *netInterface.StrategyData) {
	c.handleStrategy = hookFunc
}

//GetConn 获取客户端连接
func (c *Client) GetConn() netInterface.IConnection {
	return c.conn
}

//CallOnReceive 数据上传完成回调
func (c *Client) CallOnReceive(conn netInterface.IConnection, data []byte) {
	if c.onReceive != nil {
		c.onReceive(conn, data)
	}
}

//CallOnConnStart 调用连接OnConnStart Hook函数
func (c *Client) CallOnConnStart(conn netInterface.IConnection) {
	if c.onConnStart != nil {
		c.onConnStart(conn)
	}
}

//CallOnConnStop 调用连接OnConnStop Hook函数
func (c *Client) CallOnConnStop(conn netInterface.IConnection) {
	if c.onConnStop != nil {
		c.onConnStop(conn)
	}
}

//CallLogHandle 错误消息处理
func (c *Client) CallLogHandle(level netInterface.ErrLevel, msgAry ...interface{}) {
	if c.onLogHandle != nil {
		c.onLogHandle(level, fmt.Sprint(msgAry...))
	}
}

//SendData 发送数据给远程的TCP客户端
func (c *Client) SendData(data []byte, cmdCode string) error {
	return c.conn.SendDataCall(data, cmdCode, nil, nil)
}

//SendDataCall 发送数据给远程的TCP客户端(带参数和回调)
func (c *Client) SendDataCall(data []byte, cmdCode string, pram interface{}, callFunc func(netInterface.IConnection, []byte, bool, string, interface{}, error)) error {
	return c.conn.SendDataCall(data, cmdCode, pram, callFunc)
}

//Connect 连接到服务
func (c *Client) Connect() (bool, error) {
	if !c.config.IsTls {
		conn, err := net.Dial(c.network, c.host)
		if err != nil || conn == nil {
			return false, err
		}
		c.conn = NewConnection(c, conn, c.config)
		c.conn.Start()
		return true, nil
	}

	//tcp下的TLS带证书安全连接
	conn, err := tls.Dial(c.network, c.host, c.config.TlsConfig)

	if err != nil {
		return false, err
	}
	if conn == nil {
		return false, errors.New("未连接到连接到服务！")
	}
	//强制握手，以验证身份握手被处理，否则会在第一次读写的时候进行尝试，可能丢失数据
	err = conn.Handshake()
	if err != nil {
		return false, err
	}
	c.conn = NewConnection(c, conn, c.config)
	c.conn.Start()
	return true, nil
}

//Close 关闭
func (c *Client) Close() {
	c.conn.Stop()
}
